#ifndef m44f_h
#define m44f_h

#include "CrVec4f.h"

/// Cast m44fs to this in the debugger

class _DBm44f
{
	float x[4];
	float y[4];
	float z[4];
	float t[4];
};

///	Homogenous 4x4 matrix

/**

@ingroup Core
@ingroup Math

A homogenous matrix implementation based upon Vec4f
This will allows the optimiser to deal with things better (by holding
the elements within registers, moving constants outside of loops, etc.)

Note: 4x4 matrix has form:

| m_Xaxis[0], m_Yaxis[0], m_Zaxis[0], m_translation[0] |  
| m_Xaxis[1], m_Yaxis[1], m_Zaxis[1], m_translation[1] |
| m_Xaxis[2], m_Yaxis[2], m_Zaxis[2], m_translation[2] |
| m_Xaxis[3], m_Yaxis[3], m_Zaxis[3], m_translation[3] |

And we use standard mathematical matrix-matrix and matrix-vector 
mutiplication conventions, not the stoopid way used in some 3D graphics
books.....

**/

namespace cr
{

	class Matrix4f
	{
	public:

		Vec4f m_Xaxis,
			m_Yaxis,
			m_Zaxis,
			m_translation;

		//lint -e{1401} suppress "m_Xaxis not initialized" (etc.)

		Matrix4f()
		{
		}

		Matrix4f(Vec4f Xaxis, Vec4f Yaxis, Vec4f Zaxis, Vec4f translation = Vec4f::Zero)
		{
			m_Xaxis=Xaxis;
			m_Yaxis=Yaxis;
			m_Zaxis=Zaxis;
			m_translation=translation;
		}

		Matrix4f(const class Quaternion &q)	{ *this=q; }
		Matrix4f(const Matrix4f &base, Vec4f offset);				///<	A "child" matrix, translated in parent's space
		Matrix4f(Vec4f position, const Matrix4f &orient);			///<	A copy of a matrix (rotation only) at a different position
		Matrix4f(Vec4f direction, Vec4f up);					///<	Camera poise - both vectors MUST be normalised
		Matrix4f(float pitch, float heading, float roll);	///<	Simple Euler angles, applied in XYZ order

		void operator =(const Matrix4f &);


		// operators
		Vec4f operator *(Vec4f vert) const;			///<	Perfom a transform

		Matrix4f operator+(const Matrix4f &) const;
		void operator+=(const Matrix4f &);

		Matrix4f operator *(const float scale) const;
		void operator *=(const float scale);

		Matrix4f operator *(const Matrix4f &mat) const;
		void operator *=(const Matrix4f &mat);

		void operator=(const class Quaternion &); 

		// vector transforms
		Vec4f transform(Vec4f vert) const;			///<	Full homogenous product
		Vec4f rotate(Vec4f vert) const;				///<	3x3 only product

		//Vec4f postmultiply3x3(const Vec4f v) const;		// return (*this) * v 
		//Vec4f postmultiply4x4(const Vec4f v) const;		// return (*this) * v 

		Vec4f transpostmultiply3x3(const Vec4f v) const; ///< return (*this)^T * v 
		Vec4f transpostmultiply4x4(const Vec4f v) const; ///< return (*this)^T * v 

		Matrix4f orientation() const;		///< Returns this without translation

		// matrix ops
		// inversion
		void InverseRT(Matrix4f  &out) const;
		void InverseR(Matrix4f  &out) const;

		Matrix4f  Inverse3x3() const;
		void Inverse3x3(Matrix4f  &out) const;
		void Inverse4x4(Matrix4f  &out) const;

		// transpose
		void TransposeThis3x3();		// transpose this matrix
		void TransposeThis4x4();		//transpose this matrix
		Matrix4f Transpose3x3() const;		//transpose to another matrix
		Matrix4f Transpose4x4() const;		//transpose to another matrix

		// abs
		Matrix4f abs3x3() const;
		Matrix4f abs4x4() const;

		// add
		Matrix4f add3x3(const Matrix4f &) const;
		Matrix4f add4x4(const Matrix4f &) const;

		// scale
		Matrix4f scale3x3(const float scale) const;
		Matrix4f scale4x4(const float scale) const;

		// multiply
		void premultiply3x3(const Matrix4f &mat);			///< (*this) = mat * (*this)
		void postmultiply3x3(const Matrix4f &mat);			///< (*this) = (*this) * mat

		void premultiply4x4(const Matrix4f &mat);			///< (*this) = mat * (*this)
		void postmultiply4x4(const Matrix4f &mat);			///< (*this) = (*this) * mat

		// multiply with transposed matrix
		void premultiplyTrans3x3(const Matrix4f &mat);		///< (*this) = mat^T * (*this)
		void postmultiplyTrans3x3(const Matrix4f &mat);		///< (*this) = (*this) * mat^T 

		void premultiplyTrans4x4(const Matrix4f &mat);		///< (*this) = mat^T * (*this)
		void postmultiplyTrans4x4(const Matrix4f &mat);		///< (*this) = (*this) * mat^T

		void RotateAboutAxis(Vec4f &axis, float angle);

		// special ops
		void orthonormalise();				///< Y,Z axis are made orthogonal to X, all axes are normalised
		void orthonormaliseZ();				///< X,Y axis are made orthogonal to Z, all axes are normalised
		void skewsymmetric(const Vec4f &v);	///< turns vector into skew-sym matrix rep.
		void diagonal(const Vec4f &v);		///< vector becomes diagonal of matrix. All other entries are zero.


		void EqRotX(float angle);
		void EqRotY(float angle);
		void EqRotZ(float angle);
		void EqRotAxis(Vec4f axis, float angle);

		static Matrix4f RotX(float angle);
		static Matrix4f RotY(float angle);
		static Matrix4f RotZ(float angle);

		static Matrix4f QRotX(float angle);			///< Much faster version of RotX (uses qsin/qcos)
		static Matrix4f QRotY(float angle);			///< Much faster version of RotY (uses qsin/qcos)
		static Matrix4f QRotZ(float angle);			///< Much faster version of RotZ (uses qsin/qcos)

		static const Matrix4f Identity;				///<	{ {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} }
		static const Matrix4f IndexMatrix;			///<	  element i,j has form i.jf
		static const Matrix4f Zero;					///< 	{ {0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }
	};

}
//
//
//		Platform dependent inlines
//

//
//
//		Inlines upon inlines
//

namespace cr
{
	inline Vec4f Matrix4f::operator *(Vec4f v) const
	{
		return transform(v);
	}

	inline void Matrix4f::operator =(const Matrix4f &m)
	{
		m_Xaxis=m.m_Xaxis;
		m_Yaxis=m.m_Yaxis;
		m_Zaxis=m.m_Zaxis;
		m_translation=m.m_translation;
	}

	inline Matrix4f::Matrix4f(const Matrix4f &base, Vec4f offset)
	{
		m_Xaxis = base.m_Xaxis;
		m_Yaxis = base.m_Yaxis;
		m_Zaxis = base.m_Zaxis;
		m_translation = base * offset;
	}

	inline Matrix4f::Matrix4f(Vec4f position, const Matrix4f &orient)
	{
		m_Xaxis = orient.m_Xaxis.getXYZ_W0();
		m_Yaxis = orient.m_Yaxis.getXYZ_W0();
		m_Zaxis = orient.m_Zaxis.getXYZ_W0();
		m_translation = position.getXYZ_W1();
	}

	inline Vec4f Matrix4f::transpostmultiply3x3(const Vec4f v) const
	{
		return Vec4f( m_Xaxis.dot3(v), m_Yaxis.dot3(v), m_Zaxis.dot3(v));
	}

	inline Vec4f Matrix4f::transpostmultiply4x4(const Vec4f v) const
	{
		return Vec4f( m_Xaxis.dot4(v), m_Yaxis.dot4(v), m_Zaxis.dot4(v), m_translation.dot4(v) );
	}

	inline Matrix4f Matrix4f::add3x3(const Matrix4f &mat) const
	{
		Matrix4f m;

		m.m_Xaxis = m_Xaxis.add3(mat.m_Xaxis);
		m.m_Yaxis = m_Yaxis.add3(mat.m_Yaxis);
		m.m_Zaxis = m_Zaxis.add3(mat.m_Zaxis);

		return m;
	}

	inline Matrix4f Matrix4f::add4x4(const Matrix4f &mat) const
	{
		Matrix4f m;

		m.m_Xaxis = m_Xaxis.add4(mat.m_Xaxis);
		m.m_Yaxis = m_Yaxis.add4(mat.m_Yaxis);
		m.m_Zaxis = m_Zaxis.add4(mat.m_Zaxis);
		m.m_translation = m_translation.add4(mat.m_translation);

		return m;
	}

	inline Matrix4f Matrix4f::scale3x3(float scale) const
	{
		Matrix4f m;

		Vec4f vs=Vec4f::x(scale);
		m.m_Xaxis = m_Xaxis.mulx3(vs);
		m.m_Yaxis = m_Yaxis.mulx3(vs);
		m.m_Zaxis = m_Zaxis.mulx3(vs);
		m.m_translation = m_translation;

		return m;
	}

	inline Matrix4f Matrix4f::scale4x4(float scale) const
	{
		Matrix4f m;

		Vec4f vs=Vec4f::x(scale);
		m.m_Xaxis = m_Xaxis.mulx4(vs);
		m.m_Yaxis = m_Yaxis.mulx4(vs);
		m.m_Zaxis = m_Zaxis.mulx4(vs);
		m.m_translation = m_translation.mulx4(vs);

		return m;
	}

	inline Matrix4f Matrix4f::abs4x4() const
	{
		Matrix4f m;

		m.m_Xaxis = m_Xaxis.abs4();
		m.m_Yaxis = m_Yaxis.abs4();
		m.m_Zaxis = m_Zaxis.abs4();
		m.m_translation = m_translation.abs4();

		return m;
	}

	inline Matrix4f Matrix4f::abs3x3() const
	{
		Matrix4f m;

		m.m_Xaxis = m_Xaxis.abs3();
		m.m_Yaxis = m_Yaxis.abs3();
		m.m_Zaxis = m_Zaxis.abs3();
		m.m_translation = Vec4f::Zero;

		return m;
	}


	// matrix-matrix multiplication
	// not optimised yet...
	inline void Matrix4f::premultiply3x3(const Matrix4f &mat)
	{
		m_Xaxis = mat.rotate(m_Xaxis);
		m_Yaxis = mat.rotate(m_Yaxis);
		m_Zaxis = mat.rotate(m_Zaxis);
	}

	inline void Matrix4f::postmultiply3x3(const Matrix4f &mat)
	{
		Matrix4f m(mat);
		m.premultiply3x3( *this );
		m_Xaxis = m.m_Xaxis;
		m_Yaxis = m.m_Yaxis;
		m_Zaxis = m.m_Zaxis;
	}

	inline void Matrix4f::premultiplyTrans3x3(const Matrix4f &mat)
	{
		m_Xaxis = Vec4f(	mat.m_Xaxis.dot3(m_Xaxis),
			mat.m_Yaxis.dot3(m_Xaxis),
			mat.m_Zaxis.dot3(m_Xaxis) );

		m_Yaxis = Vec4f(	mat.m_Xaxis.dot3(m_Yaxis),
			mat.m_Yaxis.dot3(m_Yaxis),
			mat.m_Zaxis.dot3(m_Yaxis) );

		m_Zaxis = Vec4f(	mat.m_Xaxis.dot3(m_Zaxis),
			mat.m_Yaxis.dot3(m_Zaxis),
			mat.m_Zaxis.dot3(m_Zaxis) );

	}

	inline void Matrix4f::postmultiplyTrans3x3(const Matrix4f &mat)
	{
		Matrix4f m;

		m.m_Xaxis =					m_Xaxis.mulx3(mat.m_Xaxis);
		m.m_Xaxis = m.m_Xaxis.add3( m_Yaxis.mulx3(mat.m_Yaxis) );
		m.m_Xaxis = m.m_Xaxis.add3( m_Zaxis.mulx3(mat.m_Zaxis) );

		m.m_Yaxis =					m_Xaxis.muly3(mat.m_Xaxis);
		m.m_Yaxis = m.m_Yaxis.add3( m_Yaxis.muly3(mat.m_Yaxis) );
		m.m_Yaxis = m.m_Yaxis.add3( m_Zaxis.muly3(mat.m_Zaxis) );

		m.m_Zaxis =					m_Xaxis.mulz3(mat.m_Xaxis);
		m.m_Zaxis = m.m_Zaxis.add3( m_Yaxis.mulz3(mat.m_Yaxis) );
		m.m_Zaxis = m.m_Zaxis.add3( m_Zaxis.mulz3(mat.m_Zaxis) );

		(*this) = m;
	}




	inline void Matrix4f::premultiply4x4(const Matrix4f &mat)
	{
		m_Xaxis = mat.transform(m_Xaxis);
		m_Yaxis = mat.transform(m_Yaxis);
		m_Zaxis = mat.transform(m_Zaxis);
		m_translation = mat.transform(m_translation);
	}

	inline void Matrix4f::premultiplyTrans4x4(const Matrix4f &mat)
	{
		m_Xaxis = Vec4f(	mat.m_Xaxis.dot4(m_Xaxis),
			mat.m_Yaxis.dot4(m_Xaxis),
			mat.m_Zaxis.dot4(m_Xaxis),
			mat.m_translation.dot4(m_Xaxis) );

		m_Yaxis = Vec4f(	mat.m_Xaxis.dot4(m_Yaxis),
			mat.m_Yaxis.dot4(m_Yaxis),
			mat.m_Zaxis.dot4(m_Yaxis),
			mat.m_translation.dot4(m_Yaxis) );

		m_Zaxis = Vec4f(	mat.m_Xaxis.dot4(m_Zaxis),
			mat.m_Yaxis.dot4(m_Zaxis),
			mat.m_Zaxis.dot4(m_Zaxis),
			mat.m_translation.dot4(m_Zaxis) );

		m_translation = Vec4f(	mat.m_Xaxis.dot4(m_translation),
			mat.m_Yaxis.dot4(m_translation),
			mat.m_Zaxis.dot4(m_translation),
			mat.m_translation.dot4(m_translation) );
	}

	inline void Matrix4f::postmultiply4x4(const Matrix4f &mat)
	{
		Matrix4f m(mat);
		m.premultiply4x4(*this);
		(*this) = m;
	}

	inline void Matrix4f::postmultiplyTrans4x4(const Matrix4f &mat)
	{
		Matrix4f m;


		m.m_Xaxis =					m_Xaxis.mulx4(mat.m_Xaxis);
		m.m_Xaxis = m.m_Xaxis.add4( m_Yaxis.mulx4(mat.m_Yaxis) );
		m.m_Xaxis = m.m_Xaxis.add4( m_Zaxis.mulx4(mat.m_Zaxis) );
		m.m_Xaxis = m.m_Xaxis.add4( m_translation.mulx4(mat.m_translation) );

		m.m_Yaxis =					m_Xaxis.muly4(mat.m_Xaxis);
		m.m_Yaxis =	m.m_Yaxis.add4( m_Yaxis.muly4(mat.m_Yaxis) );
		m.m_Yaxis =	m.m_Yaxis.add4( m_Zaxis.muly4(mat.m_Zaxis) );
		m.m_Yaxis =	m.m_Yaxis.add4( m_translation.muly4(mat.m_translation) );

		m.m_Zaxis =					m_Xaxis.mulz4(mat.m_Xaxis);
		m.m_Zaxis =	m.m_Zaxis.add4( m_Yaxis.mulz4(mat.m_Yaxis) );
		m.m_Zaxis =	m.m_Zaxis.add4( m_Zaxis.mulz4(mat.m_Zaxis) );
		m.m_Zaxis =	m.m_Zaxis.add4( m_translation.mulz4(mat.m_translation) );

		m.m_translation =						m_Xaxis.mulw4(mat.m_Xaxis);
		m.m_translation = m.m_translation.add4( m_Yaxis.mulw4(mat.m_Yaxis) );
		m.m_translation = m.m_translation.add4( m_Zaxis.mulw4(mat.m_Zaxis) );
		m.m_translation = m.m_translation.add4( m_translation.mulw4(mat.m_translation) );
		(*this) = m;

	}



	// operators (4x4 at the moment)
	inline Matrix4f Matrix4f::operator+(const Matrix4f &mat) const
	{
		return add4x4(mat);
	}

	inline void Matrix4f::operator+=(const Matrix4f &mat)
	{
		(*this) = (*this) + mat;
	}

	inline Matrix4f Matrix4f::operator*(const float scale) const
	{
		return scale4x4(scale);
	}

	inline void Matrix4f::operator*=(const float scale)
	{
		(*this) = (*this) * scale;
	}

	inline Matrix4f Matrix4f::operator*(const Matrix4f &mat) const
	{
		Matrix4f m(mat);
		m.premultiply4x4(*this);
		return m;
	}

	inline void Matrix4f::operator*=(const Matrix4f &mat)
	{
		(*this) = (*this) * mat;
	}



	// Inverse

	// inverses which assume certain structure
	inline void  Matrix4f::InverseRT(Matrix4f  &out) const
	{
		/*
		totally unoptimized - optimize when tested
		*/
		out.m_Xaxis = Vec4f(m_Xaxis.getX(), m_Yaxis.getX(), m_Zaxis.getX(), 0.0f);
		out.m_Yaxis = Vec4f(m_Xaxis.getY(), m_Yaxis.getY(), m_Zaxis.getY(), 0.0f);
		out.m_Zaxis = Vec4f(m_Xaxis.getZ(), m_Yaxis.getZ(), m_Zaxis.getZ(), 0.0f);
		out.m_translation = -out.rotate(m_translation);
		out.m_translation.setW(1.0f);
	};

	inline void  Matrix4f::InverseR(Matrix4f  &out) const
	{
		/*
		totally unoptimized - optimize when tested
		*/
		out.m_Xaxis = Vec4f(m_Xaxis.getX(), m_Yaxis.getX(), m_Zaxis.getX(), 0.0f);
		out.m_Yaxis = Vec4f(m_Xaxis.getY(), m_Yaxis.getY(), m_Zaxis.getY(), 0.0f);
		out.m_Zaxis = Vec4f(m_Xaxis.getZ(), m_Yaxis.getZ(), m_Zaxis.getZ(), 0.0f);
	};

	// could just #include <algorithm> for the STL swap() function
	template <class _Tp>
	inline void swap_var(_Tp& __a, _Tp& __b) 
	{
		_Tp __tmp = __a;
		__a = __b;
		__b = __tmp;
	}

	inline void  Matrix4f::TransposeThis3x3()
	{
		swap_var( m_Xaxis[1], m_Yaxis[0] );
		swap_var( m_Xaxis[2], m_Zaxis[0] );
		swap_var( m_Zaxis[1], m_Yaxis[2] );
	};

	// pure inverses
	// m_Xaxis[0]*(m_Yaxis[1]*m_Zaxis[2] - m_Yaxis[2]*m_Zaxis[1])  // m_Xaxis[0]*Row[1].Cross( Row[2] ).x
	//+ m_Xaxis[1]*(m_Zaxis[0]*m_Yaxis[2] - m_Yaxis[0]*m_Zaxis[2])	// m_Xaxis[1]*Row[1].Cross( Row[2] ).y
	//+ m_Xaxis[2]*(m_Yaxis[0]*m_Zaxis[1] - m_Zaxis[0]*m_Yaxis[1]); // m_Xaxis[2]*Row[1].Cross( Row[2] ).z
	//	res[0][0] =  (m[1][1]*m[2][2]-m[1][2]*m[2][1])*D;	//  Row[1].Cross( Row[2] ).x
	//	res[1][0] =  (m[1][2]*m[2][0]-m[1][0]*m[2][2])*D;	//  Row[1].Cross( Row[2] ).y
	//	res[2][0] =  (m[1][0]*m[2][1]-m[1][1]*m[2][0])*D;	//  Row[1].Cross( Row[2] ).z
	//	res[0][1] =  (m[2][1]*m[0][2]-m[2][2]*m[0][1])*D;	//  Row[2].Cross( Row[0] ).x
	//	res[1][1] =  (m[2][2]*m[0][0]-m[2][0]*m[0][2])*D;	//  Row[2].Cross( Row[0] ).y
	//	res[2][1] =  (m[2][0]*m[0][1]-m[2][1]*m[0][0])*D;	//  Row[2].Cross( Row[0] ).z
	//	res[0][2] =  (m[0][1]*m[1][2]-m[0][2]*m[1][1])*D;	//  Row[0].Cross( Row[1] ).x
	//	res[1][2] =  (m[0][2]*m[1][0]-m[0][0]*m[1][2])*D;	//  Row[0].Cross( Row[1] ).y
	//	res[2][2] =  (m[0][0]*m[1][1]-m[0][1]*m[1][0])*D;	//  Row[0].Cross( Row[1] ).z

	inline Matrix4f  Matrix4f::Inverse3x3() const
	{
		Matrix4f res;

		float D = m_Xaxis.dot3( m_Yaxis.cross3(m_Zaxis ) );

		D = 1.0f/D;

		res.m_Xaxis = m_Yaxis.cross3( m_Zaxis );
		res.m_Xaxis*=D;

		res.m_Yaxis = m_Zaxis.cross3( m_Xaxis );
		res.m_Yaxis*=D;

		res.m_Zaxis = m_Xaxis.cross3( m_Yaxis );
		res.m_Zaxis*=D;
		res.TransposeThis3x3();
		return res;
	}

	inline void  Matrix4f::Inverse3x3(Matrix4f &res) const
	{
		res = Inverse3x3();
	};

	inline void  Matrix4f::Inverse4x4(Matrix4f &res) const
	{
		// Warning: Not a true 4x4 inverse. This assumes certain structure in the matrix.
		Inverse3x3(res);
		res.m_translation = -m_translation;
	};



	// Transpose
	inline Matrix4f Matrix4f::Transpose3x3() const
	{
		Matrix4f result;

		result.m_Xaxis = Vec4f(m_Xaxis.getX(), m_Yaxis.getX(), m_Zaxis.getX());
		result.m_Yaxis = Vec4f(m_Xaxis.getY(), m_Yaxis.getY(), m_Zaxis.getY());
		result.m_Zaxis = Vec4f(m_Xaxis.getZ(), m_Yaxis.getZ(), m_Zaxis.getZ());

		return result;
	}

	inline Matrix4f Matrix4f::Transpose4x4() const
	{
		Matrix4f result;

		result.m_Xaxis = Vec4f(m_Xaxis.getX(), m_Yaxis.getX(), m_Zaxis.getX(), m_translation.getX());
		result.m_Yaxis = Vec4f(m_Xaxis.getY(), m_Yaxis.getY(), m_Zaxis.getY(), m_translation.getY());
		result.m_Zaxis = Vec4f(m_Xaxis.getZ(), m_Yaxis.getZ(), m_Zaxis.getZ(), m_translation.getZ());
		result.m_translation = Vec4f(m_Xaxis.getW(), m_Yaxis.getW(), m_Zaxis.getW(), m_translation.getW());

		return result;
	}

	inline void Matrix4f::TransposeThis4x4()
	{
		swap_var( m_Xaxis[1], m_Yaxis[0] );
		swap_var( m_Xaxis[2], m_Zaxis[0] );
		swap_var( m_Xaxis[3], m_translation[0] );
		swap_var( m_Yaxis[2], m_Zaxis[1] );
		swap_var( m_Yaxis[3], m_translation[1] );
		swap_var( m_Zaxis[3], m_translation[2] );
	}

	// special
	inline void Matrix4f::orthonormalise()
	{
		// simple Gram-Schmidt applied to 3 3-length vectors, initialised with xaxis

		/* normalize first vector */
		m_Xaxis.normalise3();

		/* make second vector perpendicular to the first */
		float dot = m_Xaxis.dot3(m_Yaxis);
		m_Yaxis -= dot * m_Xaxis;

		/* normalize second vector */
		m_Yaxis.normalise3();

		/* third vector is first cross second */
		m_Zaxis = m_Xaxis.cross3(m_Yaxis);

		/* no need to normalize this third one since the first two are
		normalized*/
	}

	inline void Matrix4f::orthonormaliseZ()
	{
		// simple Gram-Schmidt applied to 3 3-length vectors, initialised with zaxis

		/* normalize first vector */
		m_Zaxis.normalise3();

		/* make second vector perpendicular to the first */
		float dot = m_Zaxis.dot3(m_Yaxis);
		m_Yaxis -= dot * m_Zaxis;

		/* normalize second vector */
		m_Yaxis.normalise3();

		/* third vector is first cross second */
		m_Xaxis = m_Zaxis.cross3(m_Yaxis);

		/* no need to normalize this third one since the first two are
		normalized*/
	}

	inline void Matrix4f::skewsymmetric(const Vec4f &v)
	{
		m_Xaxis = Vec4f(0.0f,v.getZ(),-v.getY());
		m_Yaxis = Vec4f(-v.getZ(),0.0f,v.getX());
		m_Zaxis = Vec4f(v.getY(),-v.getX(),0.0f);
		m_translation = Vec4f::Waxis;
	}

	inline void Matrix4f::diagonal(const Vec4f &v)
	{
		m_Xaxis = Vec4f::Xaxis * v;
		m_Yaxis = Vec4f::Yaxis * v;
		m_Zaxis = Vec4f::Zaxis * v;
		m_translation = Vec4f::Waxis * v;
	}


	// non-members
	inline Matrix4f operator *(float scale, const Matrix4f &mat)
	{
		return mat * scale;
	}

	inline void Matrix4f::EqRotX(float angle)
	{
		*this = RotX(angle);
	}

	inline void Matrix4f::EqRotY(float angle)
	{
		*this = RotY(angle);
	}

	inline void Matrix4f::EqRotZ(float angle)
	{
		*this = RotZ(angle);
	}

	inline Matrix4f Matrix4f::orientation() const
	{
		return Matrix4f(m_Xaxis, m_Yaxis, m_Zaxis, Identity.m_translation);
	}

	typedef const Matrix4f& Matrix4fRef;
}


#endif
